0x01

我们有一个业务场景是需要将用户邀请的下级用户根据其用户等级给统计出来(不止统计一级).
现有的解决方案:
mysql中一张用户表
主要的3个字段:user_id, parent _id,level,
典型的一个树形结构.
因为数据量很大,查询次数很多,所以重算这数据基本上重算一次要花个几分钟.

0x02

优化版本1:
假如我将没所有用户对应的所有直接下级用户的id取出,存放到redis中的数组,像这样

U:110->[111,112,113,...]

将用户等级也放到redis中,像这样

L:110->0

然后通过map的方式取到下级的下级用户并合并起来,再通过用户等级进行分组。

users.stream.map(u-> jedis.lrange(0,-1)).flatMap(u-> u).collect(grouppingBy(u-> jedis.get("L:" + u)))...

LRANGE
时间复杂度:O(S+N), S 为偏移量 start , N 为指定区间内元素的数量。`
优化结果:
计算机器:I5 六代 8G内存
时间:25秒

0x03

优化版本2:
使用Set存放用户,通过SUNION命令获取下级ID

时间复杂度:O(N), N 是所有给定集合的成员数量之和。

获取当前下级的用户代码则更简单了,首先将当前用户通过CPU并行的方式把SET的key计算出来,然后通过SUNION将所有的用户取出来:

private Set<String> downLevelAllUser(Set<String> users) {
    return jedis.sunion(users.parallelStream().map(s ->
            "U:" + s
    ).collect(Collectors.toList()).toArray(new String[0]));
}

这些用户的等级都查出来,那就获取他们的用户等级并进行分组.

private Map<String, List<String>> groupUser(Set<String> users) {
    return jedis.mget(users.parallelStream().map(u -> "L:" + u)
            .collect(Collectors.toList()).toArray(new String[0]))
            .parallelStream().collect(Collectors.groupingBy(r -> r));
}

主要功能都实现了,那么试试计算8级所花时间

public List<Map<String, Integer>> downLevel8UserRole(int start_user) {
        Set<String> u1 = downLevel1Users(start_user);
        Map<String, List<String>> m1 = groupUser(u1);
        Set<String> u2 = downLevelAllUser(u1);
        Map<String, List<String>> m2 = groupUser(u2);
        Set<String> u3 = downLevelAllUser(u2);
        Map<String, List<String>> m3 = groupUser(u3);
        Set<String> u4 = downLevelAllUser(u3);
        Map<String, List<String>> m4 = groupUser(u4);
        Set<String> u5 = downLevelAllUser(u4);
        Map<String, List<String>> m5 = groupUser(u5);
        Set<String> u6 = downLevelAllUser(u5);
        Map<String, List<String>> m6 = groupUser(u6);
        Set<String> u7 = downLevelAllUser(u6);
        Map<String, List<String>> m7 = groupUser(u7);
        Set<String> u8 = downLevelAllUser(u7);
        Map<String, List<String>> m8 = groupUser(u8);
        return Arrays.asList(m1, m2, m3, m4, m5, m6, m7, m8).parallelStream().map(m -> {
            Map<String, Integer> newMap = new HashMap<>();
            m.forEach((k, v) -> newMap.put(k, v.size()));
            return newMap;
        }).collect(Collectors.toList());
    }

优化结果:
总用户数为:120W
计算机器:I5 六代 8G内存
时间:4秒

好了,优化完毕了,大神们还有什么高招,欢迎来指导!!!!!!


0x1024
70 声望7 粉丝

« 上一篇
接口调试杀器